package com.huiyeji.dynamic.core;

import com.huiyeji.dynamic.core.bean.*;
import com.huiyeji.dynamic.core.builder.DynamicBuilder;

import java.util.*;

/**
 * @author Huiyeji
 */
public class DynamicObjectFactory{

    public static final DynamicBuilder builder = DynamicBuilderManager.Anno;

    public static final DynamicBuilder staticBuilder = DynamicBuilderManager.Static;

    private static final List<DynamicObject> GLOBAL_DYNAMIC_OBJECTS = Arrays.asList(
            builder.build(new DynamicString()),
            builder.build(new DynamicClass()),
            builder.build(new DynamicJson()),
            builder.build(new DynamicMap()),
            builder.build(new DynamicObjects()),
            builder.build(new DynamicList()),
            builder.build(new DynamicInteger()),
            builder.build(new DynamicLong()),
            builder.build(new DynamicBoolean()),
            builder.build(new DynamicR3Coder()),
            builder.build(new DynamicR2Coder())
    );

    private final Map<String, DynamicObjectItem> dynamicObjectMap = new HashMap<String, DynamicObjectItem>();

    protected DynamicObjectFactory(List<DynamicObject> globalDynamicObjects){
        _register(builder.build(builder), true);
        _register(builder.build(staticBuilder), true);
        globalRegisterBean();
        if (globalDynamicObjects != null){
            for (DynamicObject dynamicObject : globalDynamicObjects) {
                _register(dynamicObject,true);
            }
        }
    }

    private void globalRegisterBean(){
        //注册全局dynamic组件
        for (DynamicObject globalDynamicObject : GLOBAL_DYNAMIC_OBJECTS) {
            _register(globalDynamicObject,true);
        }
    }

    public static DynamicObjectFactory createFactory(List<DynamicObject> globalDynamicObjects){
        return new DynamicObjectFactory(globalDynamicObjects);
    }

    public static DynamicObjectFactory createFactory(DynamicObject... globalDynamicObjects){
        return createFactory(Arrays.asList(globalDynamicObjects));
    }

    public static DynamicObjectFactory createFactory(){
        return new DynamicObjectFactory(null);
    }

    public void registerDynamicObject(DynamicObject dynamicObject){
        _register(dynamicObject,false);
    }

    protected void registerDynamicContext(DynamicContext context){
        //注册全局上下文对象
        _register(builder.build(context),true);
        //注册程序控制器
        _register(builder.build(new DynamicProgram(context)), true);
        //注册监听器
        _register(builder.build(context.getMonitor()), true);
        //注册插件管理器
        _register(builder.build(context.getPluginManager()), true);
    }

    protected void registerBuilder(DynamicBuilder builder){
        _register(DynamicObjectFactory.builder.build(builder),true);
    }

    protected void _register(DynamicObject dynamicObject,boolean isGlobal){
        _register(dynamicObject.getDynamicObjectName(),dynamicObject,isGlobal);
    }

    protected void _register(String name,DynamicObject dynamicObject,boolean isGlobal){
        if (dynamicObject == null){
            return;
        }
        if (containsDynamicObject(name)){
            DynamicObjectItem dynamicObjectItem = dynamicObjectMap.get(name);
            if (dynamicObjectItem.isGlobal()){
                throw new RuntimeException("dynamic object 【"+name+"】 is global (read only), register error !");
            }
            dynamicObjectItem.setDynamicObject(dynamicObject);
        } else {
            dynamicObjectMap.put(name, new DynamicObjectItem(dynamicObject,isGlobal));
        }
    }

    public void removeDynamicObject(String dynamicName){
        dynamicObjectMap.remove(dynamicName);
    }

    public DynamicObject getDynamicObject(String dynamicName){
        if (!containsDynamicObject(dynamicName)){
            return null;
        }
        return dynamicObjectMap.get(dynamicName).getDynamicObject();
    }

    public boolean containsDynamicObject(String dynamicName){
        return dynamicObjectMap.containsKey(dynamicName);
    }

    protected Map<String, DynamicObject> getDynamicObjectMap(){
        Map<String, DynamicObject> map = new HashMap<>();
        for (Map.Entry<String, DynamicObjectItem> entry : dynamicObjectMap.entrySet()) {
            map.put(entry.getKey(), entry.getValue().getDynamicObject());
        }
        return map;
    }

    protected Map<String, DynamicObject> getGlobalDynamicObjectMap(){
        Map<String, DynamicObject> map = new HashMap<>();
        for (Map.Entry<String, DynamicObjectItem> entry : this.dynamicObjectMap.entrySet()) {
            if (entry.getValue().isGlobal()){
                map.put(entry.getKey(), entry.getValue().getDynamicObject());
            }
        }
        return map;
    }

    protected void tempClear(){
        Iterator<Map.Entry<String, DynamicObjectItem>> iterator = dynamicObjectMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, DynamicObjectItem> entry = iterator.next();
            if (!entry.getValue().isGlobal()){
                iterator.remove();
            }
        }
    }

    protected void _globalization() {
        for (Map.Entry<String, DynamicObjectItem> entry : dynamicObjectMap.entrySet()) {
            entry.getValue().setGlobal(true);
        }
    }
}
